package cn.com.zero.common.gateway.handler;

import cn.com.zero.base.config.ReturnCodeConfig;
import cn.com.zero.base.exception.ErrorCodeException;
import cn.com.zero.base.vo.ResponseVO;
import cn.hutool.json.JSONUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import reactor.netty.ByteBufMono;

import java.util.Map;

/**
 * @author Yang Yao
 * @version 1.0.0
 * @Description 全局异常处理器
 * @createTime 2023/2/28 14:27
 */
@Component
@Order(-1) // 保证优先级高于默认的 Spring Cloud Gateway 的 ErrorWebExceptionHandler 实现
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {

    /**
     * 输出日志对象
     */
    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    private ReturnCodeConfig returnCodeConfig;

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        // 已经 commit，则直接返回异常
        ServerHttpResponse response = exchange.getResponse();
        if (response.isCommitted()) {
            return Mono.error(ex);
        }
        ResponseVO responseVO = new ResponseVO();
        Map<String, String> codeAndMessageMap = returnCodeConfig.getRoot();

        // 判断是否是无权限访问异常
        if (ex instanceof ErrorCodeException) {
            ErrorCodeException e = (ErrorCodeException) ex;
            long code = e.getCode();
            responseVO.setCode(code);
            responseVO.setMessage(codeAndMessageMap.get(String.valueOf(code)));
        } else {
            logger.error("未知异常", ex);
            responseVO.setCode(-999999L);
            responseVO.setMessage("系统发生错误，请联系管理员！！！");
        }
        DataBuffer dataBuffer = response.bufferFactory().allocateBuffer().write(JSONUtil.toJsonStr(responseVO).getBytes());
        response.setStatusCode(HttpStatus.OK);
        response.getHeaders().setContentType(MediaType.APPLICATION_NDJSON);

        // 返回给前端
        return response.writeAndFlushWith(Mono.just(ByteBufMono.just(dataBuffer)));
    }

    @Autowired
    public void setReturnCodeConfig(ReturnCodeConfig returnCodeConfig) {
        this.returnCodeConfig = returnCodeConfig;
    }
}
